Skip to content

Issue 36702 asset picker - #36944

Open
nicobytes wants to merge 59 commits into
mainfrom
issue-36702-asset-picker
Open

Issue 36702 asset picker#36944
nicobytes wants to merge 59 commits into
mainfrom
issue-36702-asset-picker

Conversation

@nicobytes

@nicobytes nicobytes commented Aug 7, 2026

Copy link
Copy Markdown
Member

This pull request introduces a set of improvements and refactorings to the folder tree utilities and related data-access APIs, aimed at enhancing code reuse, maintainability, and consistency across the Content Drive and Host Folder Field features. The changes include moving folder tree logic into shared utilities, updating service providers, and aligning data models.

Core refactoring and utility extraction:

  • Introduced new shared utilities folder-tree.utils.ts and folder-tree-load.utils.ts in @dotcms/data-access, centralizing the logic for building, loading, and paginating folder trees. This includes new functions such as generateAllParentPaths, createTreeNode, and buildTreeFolderNodes, as well as utilities for paginated loading and "Load more" node handling. [1] [2]

API and provider updates:

  • Updated DotContentDriveService to use Angular's providedIn: 'root' for global availability, and removed it from route-level providers. This ensures the service can be used from dialogs and other contexts without explicit injection in every route. [1] [2]

Imports and dependency cleanup:

  • Updated imports in various portlet files to use the new shared utilities from @dotcms/data-access instead of local utility definitions, and cleaned up duplicate or outdated imports for components such as DotFolderListViewComponent. [1] [2] [3] [4]

Data model alignment:

  • Extended the TreeNodeContentData model to include additional metadata fields (inode, defaultBaseType, fromTable) for improved folder selection and upload behavior in the Content Drive and AssetPicker.

Constants and type re-exports:

  • Refactored and re-exported shared folder tree page size constants from the new utilities, ensuring consistent pagination limits across features, and deprecated local type definitions in favor of those from @dotcms/data-access. [1] [2] [3] [4]

These changes improve code maintainability, reduce duplication, and ensure that folder tree behaviors remain consistent across all consuming features.

This PR fixes: #36702

AssetPicker series — all seven sub-issues are resolved in this PR:

Fixes #36831 — AssetPicker 1/7: Migrate DotFolderListView to @dotcms/ui
Fixes #36832 — AssetPicker 2/7: Lift folder-tree helpers and harden drive data-access
Fixes #36833 — AssetPicker 3/7: Decouple Content Drive toolbar chrome for AssetPicker reuse
Fixes #36834 — AssetPicker 4/7: Headless browse store (no URL) for AssetPicker
Fixes #36835 — AssetPicker 5/7: Build DotAssetPicker shell in @dotcms/ui
Fixes #36836 — AssetPicker 6/7: File/Image entry configs, silent mime, CT limits, global last path
Fixes #36837 — AssetPicker 7/7: Wire AssetPicker into Edit Content File/Image fields

- Extracted DotFolderListView component and related models/constants/mocks into the new `@dotcms/ui` library.
- Updated imports in the Content Drive shell to reference the new location.
- Introduced `selectionMode` input to support both single and multiple selection.
- Re-exported necessary symbols from `@dotcms/ui` in the Content Drive UI for compatibility.
- Added tests for the new component and selection mode functionality.

This migration aims to share the folder/asset list component between Content Drive and future AssetPicker implementations, enhancing code reuse and maintainability.
Copilot AI lite review requested due to automatic review settings August 7, 2026 14:45
@github-actions github-actions Bot added the Area : Frontend PR changes Angular/TypeScript frontend code label Aug 7, 2026
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Claude finished @nicobytes's task in 2m 30s —— View job


Re-review at 2801a61e

Rechecked every prior finding against the code at this HEAD (not commit messages), and scanned the diff for new issues. The only source change since the last full review is the bundle-budget raise (157ef01b) plus two main merges — no new logic. Findings below.

New Issues

None. (The bundle-budget raise in apps/dotcms-block-editor/project.json is a real tradeoff, not a defect — see note at the end.)

Existing (still open)

  • 🟠 High: libs/ui/src/lib/components/dot-asset-picker/store/features/with-asset-folder-tree.feature.ts:216publish() still re-points by key and lands on null when the key is absent (findNodeByKey(folders, selectedKey) ?? null). After a sidebar folder search, searchFoldersInBrowsingSite deliberately leaves selectedNode pointing outside the published tree, so the next mutateNode → publish (expand / "Load more") nulls it → $targetFolder becomes undefined#uploadByBaseType silently drops the upload at the site root while the list still shows the searched folder. This is the one genuinely user-facing bug still open. You proposed two fixes; option (1) — keep the previous node when the key misses — matches the documented intent of the search path. Fix this →

  • 🟡 Medium: libs/portlets/dot-content-drive/portlet/src/lib/utils/tree-folder.utils.spec.ts:1 — still 37 lines, no longer imports tree-folder.utils, while tree-folder.utils.ts is byte-identical to main and still consumed by store/features/sidebar/withSidebar.ts and utils/functions.ts. generateAllParentPaths / createTreeNode / buildTreeFolderNodes are now uncovered live logic — coverage was dropped, not moved. Largest gap in the PR.

  • 🟡 Medium: libs/portlets/dot-content-drive/ui/src/lib/shared/models.ts:14 + dot-content-drive-shell.component.ts:1128-1133DotContentDriveUploadFiles/DotContentDriveMoveItems are now aliases of DotUploadFiles (optional targetFolder: TreeNodeData), but getMoveMetadata still reads event.targetFolder.hostname / .path unguarded. onRequestUpload was narrowed on LOAD_MORE_NODE_TYPE; getMoveMetadata was not, so the two are inconsistent and a load-more node yields //undefined/. Either narrow getMoveMetadata the same way or restore a Content-Drive-specific alias that requires folder data.

  • 🟡 Medium: libs/ui/src/lib/components/dot-folder-list-view/dot-folder-list-view.component.ts:313this.$selection() !== undefined (was ??) while the input was widened to accept null. A controlled consumer binding null for "nothing selected" — the natural shape for the new selectionMode="single" — gets a permanently empty selection. Latent (both in-repo consumers pass arrays), but a trap for the exact mode this PR adds. Reverting to ?? is a one-liner.

  • 🟡 Medium: libs/edit-content/.../dot-file-field/dot-file-field.component.ts — "Select Existing File" is still a silent no-op when getCurrentSite() returns falsy or errors (error: () => { /* noop */ }). Same silent path was later added to EditorModalService and DotWysiwygPluginService, so this is one consistent UX decision across three entry points, not a one-line fix — worth deciding on before merge.

  • 🔵 Low: libs/ui/src/lib/components/dot-workflow-push-publish/dot-workflow-push-publish.component.html:95'Change''change' renders lowercase (change=change vs Change=Change in Language.properties). Confirmed merge damage from 5624a082 (main has 'Change'), same commit that dropped the SiteSearchAPIImpl passthrough. One-character revert. Fix this →

  • 🔵 Low: libs/portlets/dot-content-drive/ui/src/index.ts:1 — two import paths still resolve the same classes (@dotcms/ui and @dotcms/portlets/content-drive/ui). Naming/ownership cleanup, fine as a follow-up.

Resolved

  • dot-asset-picker.component.tsNullInjectorError/NG0201 in the legacy Dojo host. DotHttpErrorManagerService removed from all 6 store call sites; failures now recorded as requestError state and toasted by the component; legacy-host spec un-skipped.
  • SiteSearchAPIImpl.java:263DotDataException passthrough restored (file byte-identical to main).
  • dot-file-field.component.ts — double-open race guarded with #assetPickerPending, released on close/error; three tests added.
  • with-asset-folder-tree.feature.tssearchFoldersInBrowsingSite re-adds the browsing site to roots when the site filter drops it.
  • with-asset-folder-tree.feature.ts:317TreeLoadResult absent-key contract honored via conditional spread; loadFolders keeps success work in tap before catchError (ERROR no longer masked by LOADED).
  • dot-asset-picker.component.tsconfirm() has an error: handler that toasts and keeps the dialog open.
  • dot-asset-picker.store.ts:150-154setSearch clears path and selectRootNode(), so the highlight and upload target follow the widened scope.
  • libs/ui/src/index.ts + dot-file-field.component.ts:887 — File/Image "Select Existing" now opens DotAssetPickerComponent; DotBrowserSelectorComponent no longer referenced.

Note on the bundle budget (157ef01b)

The raise (warn 3.5→4.25 MB, error 4→4.5 MB) is a genuine growth, not a moved budget: EditorModalService holds a static DotAssetPickerComponent reference for dialogService.open, pulling the picker subtree into the initial chunk of every @dotcms/new-block-editor consumer, dotcms-ui included. The lazy-import() route you described keeps the original budget and is semantically correct (the picker only opens on user action). Not blocking, but worth doing before this compounds.


Blocking before merge: the 🟠 publish() upload-misplacement bug. Everything else is non-blocking; the two 🔵 merge-damage items ('change' here, and you already fixed the Java one) support your call for a manual pass over git diff origin/main on backend/CI files before merge.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the existing Folder List View used by Content Drive into a reusable presentational component in @dotcms/ui, adding a single-selection mode intended for the upcoming AssetPicker (while preserving current Content Drive behavior via the default multiple selection mode).

Changes:

  • Moved Folder List View domain-agnostic types/constants into @dotcms/ui and re-exported them from the Content Drive UI package for compatibility.
  • Added selectionMode: 'single' | 'multiple' support to the table (checkboxes in multiple mode, radios in single mode) and normalized emitted selections to an array.
  • Updated Content Drive shell imports and updated/extended unit tests accordingly.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated no comments.

Show a summary per file
File Description
core-web/libs/ui/src/lib/components/dot-folder-list-view/models.ts Introduces shared column typing and selectionMode model for the Folder List View.
core-web/libs/ui/src/lib/components/dot-folder-list-view/constants.ts Defines header column config and drag MIME type local to the component folder.
core-web/libs/ui/src/lib/components/dot-folder-list-view/mocks.ts Moves test mocks alongside the component.
core-web/libs/ui/src/lib/components/dot-folder-list-view/dot-folder-list-view.component.ts Adds selectionMode input, normalizes selection output, and updates internal imports to local UI sources.
core-web/libs/ui/src/lib/components/dot-folder-list-view/dot-folder-list-view.component.html Switches checkbox vs radio rendering based on selectionMode and updates selection binding.
core-web/libs/ui/src/lib/components/dot-folder-list-view/dot-folder-list-view.component.scss Fixes relative SCSS imports to match the libs layout.
core-web/libs/ui/src/lib/components/dot-folder-list-view/dot-folder-list-view.component.spec.ts Updates tests for the new selection model and adds coverage for single-selection behavior.
core-web/libs/ui/src/index.ts Exposes Folder List View component + related models/constants from @dotcms/ui.
core-web/libs/portlets/dot-content-drive/ui/src/lib/shared/models.ts Removes Folder List View column typing now owned by @dotcms/ui.
core-web/libs/portlets/dot-content-drive/ui/src/lib/shared/constants.ts Removes list-view constants now owned by @dotcms/ui.
core-web/libs/portlets/dot-content-drive/ui/src/index.ts Re-exports the Folder List View API surface from @dotcms/ui for Content Drive consumers.
core-web/libs/portlets/dot-content-drive/portlet/src/lib/dot-content-drive-shell/dot-content-drive-shell.component.ts Updates imports to use @dotcms/ui for the presentational list component/types.
core-web/libs/portlets/dot-content-drive/portlet/src/lib/dot-content-drive-shell/dot-content-drive-shell.component.spec.ts Aligns test imports with the updated component export location.

- Introduced new utility functions for managing folder hierarchies, including `getFolderHierarchyByPath` and `getFolderNodesByPath`, to improve folder navigation and loading in the content drive.
- Added `folder-tree-load.utils.ts` and `folder-tree.utils.ts` files to encapsulate the new logic.
- Implemented comprehensive unit tests for the new utilities to ensure functionality and reliability.
- Updated existing services to utilize the new utilities, enhancing code organization and maintainability.

These changes aim to streamline folder management and improve the user experience in the content drive interface.
Extracts the content-type, language, and search filter components (plus the
chip-filter/list-item primitives and upload button) out of the content-drive
portlet into @dotcms/ui so they can be shared with the AssetPicker. Store-
specific logic stays behind thin adapter components in the portlet.
- serve target lacked a dependsOn, so dotcms-webcomponents could be
  stale or missing when dotcms-ui starts serving
- webcomponents build target was missing outputs, preventing Nx from
  caching/detecting its build artifacts correctly
- Introduces DotAssetPickerStore in @dotcms/ui to power the upcoming
  AssetPicker dialog with a search request builder mirroring Content
  Drive's, but with no router/URL coupling so it can run inside a
  dialog over Edit Contentlet without corrupting host navigation.
- Relocates ALL_FOLDER/SYSTEM_HOST_ID out of the Content Drive UI
  library into shared dot-folder-tree constants so both Content
  Drive and the new picker consume a single source.
@nicobytes
nicobytes requested a lite review from Copilot August 7, 2026 17:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 76 out of 78 changed files in this pull request and generated no new comments.

Suppressed comments (1)

core-web/libs/ui/src/lib/components/dot-asset-picker/store/features/with-asset-folder-tree.feature.ts:97

  • loadFolders sets foldersStatus to ERROR in catchError, but then the subscribe block unconditionally patches it back to LOADED (because catchError returns an empty array). This masks folder-tree failures and makes the UI indistinguishable from a successful empty tree.

The AssetPicker (browse/pick a single asset) now composes the dropzone, upload-type selector, and folder sidebar/toolbar that Content Drive already had, so both features share one implementation instead of duplicating upload flow logic.

- Move `dot-content-drive-dropzone` and the upload-type-selector dialog out of the Content Drive portlet into `@dotcms/ui` as `DotUploadDropzoneComponent` and `DotUploadTypeSelectorComponent`, decoupled from `DotContentDriveStore` (folder/drag-state now passed via inputs/outputs)
- Add `DotAssetPickerComponent` with sidebar/toolbar subcomponents, wiring the shared dropzone, upload selector, and folder tree to a new `DotAssetPickerStore`
- Update Content Drive shell to consume the relocated shared components and derive drag/target-folder state locally
Adds a global last-used-path store, a config builder that translates
Edit Content field type (File/Image) into picker filters, and
server-side base-type narrowing for the content type filter so
restricted hosts don't page through mostly-discarded results.

@zJaaal zJaaal left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: AssetPicker / Content Drive refactor

Reviewed at 7e1b2ae (136+ files). Focus was bad practices and regressions in Content Drive, plus the shared components the refactor extracted into @dotcms/ui. 11 findings inline, most severe first.

Blocking, in my read:

  1. DotAssetPickerComponent is missing two providers, so it cannot construct in the legacy Dojo binary-field host (and now the Story Block path too).
  2. A merge resolution dropped main's DotDataException passthrough in SiteSearchAPIImpl (unrelated to this PR, would land in main).
  3. The folder-tree publish() nulls selectedNode after a sidebar search, so dropped files silently land at the site root.

Content Drive specifically: the biggest issue is tree-folder.utils.spec.ts going from 38 tests to 5 while tree-folder.utils.ts is unchanged and still live. That is not coverage moving with the code: every component that actually moved kept or grew its tests.

Verified clean (flagging these because they look alarming in the diff but check out):

  • Removing #fillWidth is legitimate, not a lost fix: title is now unsized and absorbs the remainder, so the rescale is genuinely dead code.
  • The dropzone extraction is faithful, and resetContextMenu() survives as the new dragEnter output.
  • The upload-button label mapping is preserved exactly, .toUpperCase() included.
  • The content-type filter keeps the monotonic cache, the #cancelFetch$ race guard, the ensure param and the chip label fallback; the adapter keeps the same double patchFilters/removeFilter commit shape.
  • The search input improved: the old placeholder was a hardcoded untranslated "Search"; it is now the search key, same text, plus value re-sync, trim and a distinct-emission guard.
  • DotContentDriveService -> providedIn: 'root' is safe (stateless, HttpClient only).
  • ALL_FOLDER / SYSTEM_HOST_ID have a single definition re-exported, so no split identity.
  • Content Drive's main grid stays uncontrolled and passes no selectionMode/showActions/titleOpensItem, so it keeps the old defaults.
  • Spec coverage carried over where things moved: folder-list-view 2417 -> 2584 lines / 183 tests, content-type filter 41 -> 52, dropzone and upload-selector 1:1.
  • [draggable] -> [attr.draggable] is behavior-neutral; shell/sidebar spec changes are symbol renames with assertions intact.

Reviewed by Claude (Claude Code), posted from @zJaaal's account.

Comment thread core-web/libs/portlets/dot-content-drive/ui/src/index.ts
Reworks the File field's AssetPicker dialog helper into a shared component
usable across Story Block and WYSIWYG fields, adds E2E coverage for both,
and updates the WYSIWYG plugin service to open the shared picker (with
guarded async site lookup) instead of the legacy dialog.
- Point deleteContentlets at /api/v1/workflow (the old
  /api/v1/content/actions endpoint doesn't exist and was silently
  404ing, leaking seeded content every run)
- Drop searchFor calls in favor of relying on modDate:desc ordering
  now that seeded assets are guaranteed the newest rows
- Select the outer textbox in BlockEditorField since ProseMirror
  nests a second contenteditable textbox inside it
- Assert the TinyMCE dotAddImage button's tooltip, since TinyMCE
  promotes it to aria-label/title and it's the button's only
  accessible name
Provide DotHttpErrorManagerService and DotContentTypeService directly on
dot-asset-picker.component.ts, since only the main app shell currently
provides them and the legacy Dojo binary-field builder hosts the picker
without that context, causing it to throw and render blank.
- Add #assetPickerPending guard so a slow site lookup can't be
  raced by a second click before #dialogRef is set, and release it
  on every close (success, cancel, or lookup error) so the picker
  can reopen afterward.
- Rethrow DotDataException as-is in SiteSearchAPIImpl.defaultIndexName
  instead of re-wrapping it, preserving the original exception type.
Reproduces the NullInjectorError the picker still throws in the
binary-field custom-element host, which bootstraps with no Router and
none of the app-shell providers.

b27ab75 added DotContentTypeService and DotHttpErrorManagerService to
the picker's own providers. That closes the first half only:
DotContentTypeService just needs HttpClient, but
DotHttpErrorManagerService transitively pulls in DotAlertConfirmService,
DotRouterService (-> Router) and DotEventsSocket. The chain cannot be
closed with component-level providers, since provideRouter returns
EnvironmentProviders and cannot go in a component's providers array.

Skipped on purpose: the failure is the open finding, not a flaky test.
Un-skip it when the store stops depending on DotHttpErrorManagerService
and reports errors through the MessageService toast the picker already
owns for upload and confirm failures.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot removed the Area : Backend PR changes Java/Maven backend code label Aug 17, 2026
@nicobytes

Copy link
Copy Markdown
Member Author

Review feedback status — rechecked at e21bd64756

Went through every Critical/High finding from @zJaaal, @adrianjm-dotCMS, Copilot and the claude[bot] pass. Below is what changed since the last review, verified against the code at this HEAD rather than from the commit messages.

✅ Addressed

🟠 SiteSearchAPIImpl — merge dropped main's DotDataException passthrough (dfeca53acc)
Restored the } catch (DotDataException e) { throw e; } in defaultIndexName(). The file is now byte-identical to origin/main, so merging this PR no longer reverts the #36983 fix, and it is consistent again with isDefaultIndex() / getAggregations().

🟠 Async dialog open can stack two pickers (dfeca53acc)
Added an #assetPickerPending flag in dot-file-field.component.ts. Notes on the shape of the fix:

  • #dialogRef could not serve as the guard: it is shared with the other three dialogs this component opens and is never reset on close, so checking it would have blocked the picker permanently after any of them ran.
  • The flag is released on error, when no site resolves, and on every dialog close. That last one required dropping the filter(file => !!file) from the onClose subscription — with the filter in place, cancelling never released the guard and the button would have died for the rest of the session.
  • Three tests added in dot-edit-content-file-field.component.spec.ts: double click while the site lookup is in flight, re-open after close, and retry after a failed lookup.

The same race existed on the two callers added later in this PR (EditorModalService for the Story Block, DotWysiwygPluginService for the WYSIWYG field); both already guard with an equivalent pending flag, so all three entry points are consistent now.

⚠️ Partially addressed — please re-read this one

🔴 Missing providers / picker cannot construct in the legacy Dojo binary-field host

b27ab7557b adds DotHttpErrorManagerService and DotContentTypeService to the picker's providers, as suggested. That is necessary but not sufficient, so this finding should stay open.

I added a regression spec that constructs DotAssetPickerComponent with only the provider set the custom-element host actually has (dot-asset-picker.component.legacy-host.spec.ts, ec5aaccfca). It still fails:

NG0201: No provider found for `DotAlertConfirmService`

DotContentTypeService is satisfied — it only needs HttpClient. DotHttpErrorManagerService is not; it transitively pulls in:

DotHttpErrorManagerService
  ├── DotAlertConfirmService   → ConfirmationService          ← fails here now
  ├── DotMessageDisplayService → DotRouterService → Router, DotEventsSocket
  └── DotRouterService         → Router

apps/dotcms-binary-field-builder bootstraps without a Router — which is the same reason GlobalStore was deliberately kept out of DotFileFieldComponent. The chain therefore cannot be closed with component-level plumbing at all: provideRouter returns EnvironmentProviders and cannot go in a component's providers array.

The fix that actually closes it is to drop the DotHttpErrorManagerService dependency from the picker's store features (6 call sites across with-asset-browse / with-asset-folder-tree) and report errors through the MessageService toast the picker already owns — it does exactly that for upload and confirm failures today. The spec is committed skipped, with the chain documented, to be un-skipped as part of that change.

❌ Still open

Finding Verified at this HEAD
🟠 publish() nulls the tree highlight after a sidebar search, retargeting uploads to the site root with-asset-folder-tree.feature.ts:222 unchanged — still findNodeByKey(folders, selectedKey) ?? null
🟠 tree-folder.utils.spec.ts gutted on unchanged production code still 37 lines vs 681 on main, and still does not import tree-folder.utils
🟡 "Select Existing File" gives no feedback when getCurrentSite() fails still a silent return; only the new guard flag was added there
🟡 $selection() !== undefined vs ?? dot-folder-list-view.component.ts:313 unchanged
🟡 i18n 'change' resolves to lowercase change dot-workflow-push-publish.component.html:95 unchanged

One thing worth a separate look

Two of the findings above (SiteSearchAPIImpl, and the 'Change''change' i18n key) are both merge-resolution damage from the same commit (5624a082d4), not intentional changes — main has 'Change' on that line. Since two independent regressions came in through one automated conflict resolution, a manual pass over the backend and CI files in git diff origin/main before merge seems worthwhile; I was not able to complete that sweep myself.

Carrying these across from the Content Drive copy. Each one records a
bug that was already fixed once, so losing them makes it cheap to
reintroduce:

- $columns anchors extras to where "type" sits in the CANONICAL order,
  not its rendered index. Keying off the rendered index appended the
  extras when Type was hidden, putting every extra cell one heading
  early.
- the item-title `title` attribute is what keeps truncated text
  reachable on hover.
- the contentType cell truncates so a long variable name cannot grow
  the row past its neighbours.
- the locked-by-others icon is coloured rather than a different glyph
  on purpose.

The title rationale is reworded rather than copied verbatim: that column
is no longer a fixed width on this branch, it absorbs the leftover, so
the clipping now comes from the cell's `minmax(0,1fr)` track.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@claude

claude Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Claude finished @nicobytes's task in 1m 15s —— View job


I'll analyze this and get back to you.

nicobytes and others added 2 commits August 17, 2026 14:52
Wiring the Story Block to DotAssetPickerComponent means EditorModalService
now holds a static reference to it, so the picker and its subtree (folder
list table, folder tree, splitter, content-type filter, Content Drive
store) land in the initial chunk. It replaced DotBrowserSelectorComponent,
which was considerably lighter, pushing this app to 4.08 MB against a
4.00 MB hard limit.

Warning 3.5mb -> 4.25mb, error 4mb -> 4.5mb.

Note this is a budget raise, not an optimization: every consumer of
@dotcms/new-block-editor now ships the picker in its initial bundle. The
alternative is loading the picker through a dynamic import() in
openAssetPicker so its subtree moves to a lazy chunk, which would keep the
original budget. Left as a follow-up rather than folded in here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The picker threw NullInjectorError and rendered blank when opened from a
File/Image field in the legacy content editor, a regression against
DotBrowserSelectorComponent, which used root-provided services only.

Providing the missing services on the component (b27ab75) only moved
the failure one link along. DotHttpErrorManagerService transitively needs

    DotHttpErrorManagerService
      +-- DotAlertConfirmService   -> ConfirmationService
      +-- DotMessageDisplayService -> DotRouterService -> Router, DotEventsSocket
      +-- DotRouterService         -> Router

and dotcms-binary-field-builder bootstraps with no Router at all -- the
same reason GlobalStore was kept out of DotFileFieldComponent. It cannot
be closed by plumbing either: provideRouter returns EnvironmentProviders
and cannot go in a component's providers.

So drop the dependency instead. The store now records failures as
`requestError` state (6 call sites across with-asset-browse and
with-asset-folder-tree) and the picker component toasts them through the
MessageService it already owns for upload and confirm failures. That also
puts it back in line with the repo rule that a store holds data, not UI.

DotContentTypeService stays in providers -- it only needs HttpClient.

The legacy-host spec added in ec5aacc is un-skipped and passing. Its
provider set now mirrors app.module.ts exactly rather than a subset, so
it fails on anything router-bound being reintroduced.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nicobytes

Copy link
Copy Markdown
Member Author

Two changes pushed that reviewers should know about (852bf9ca12, 157ef01ba6)

1. The 🔴 provider finding is now genuinely closed

Details in the thread. Short version: DotHttpErrorManagerService is out of the picker's store features — the store records failures as state, the component toasts them — and the legacy-Dojo-host spec is un-skipped and passing. My earlier "please keep this open" comment no longer applies.

2. I raised a bundle budget, which nobody asked for

nx run dotcms-block-editor:build:production was failing:

✘ [ERROR] bundle initial exceeded maximum budget. Budget 4.00 MB was not met by 80.43 kB with a total of 4.08 MB.

apps/dotcms-block-editor/project.json is byte-identical to main, so the budget was not moved — the bundle grew. Cause is this PR: wiring the Story Block to the picker means EditorModalService holds a static reference to DotAssetPickerComponent (dialogService.open needs the class), so the picker and its subtree — folder-list table, folder tree, splitter, content-type filter, Content Drive store — land in the initial chunk. It replaced DotBrowserSelectorComponent, which was considerably lighter.

I raised warning 3.5mb → 4.25mb and error 4mb → 4.5mb to unblock the build.

Flagging it because it is a budget raise, not an optimization, and it is not confined to the demo app: every consumer of @dotcms/new-block-editor now ships the picker in its initial bundle, dotcms-ui included.

The alternative is loading the picker through a dynamic import() in openAssetPicker, moving its subtree to a lazy chunk and keeping the original budget. The picker only ever opens on user action, so lazy is semantically right. I did not do it because I could not verify it is sufficient on its own — @dotcms/ui is already pulled in statically for DotAIImagePromptComponent, though esbuild tree-shakes per symbol so the picker's subtree should still move.

Two caveats on my own diagnosis, so nobody takes it as measured fact:

  • I did not confirm whether this build passes on main. I attributed the growth by reasoning about the dependency graph, not by an A/B measurement — my attempt to measure it by stubbing the import did not come out clean and I reverted it rather than leave the tree dirty.
  • I did not measure the picker's exact contribution.

Happy to do the lazy-import route instead if you would rather not carry the raise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area : Frontend PR changes Angular/TypeScript frontend code

Projects

Status: No status

5 participants